#pragma once
#include <iostream>
#include <unordered_map>
#include <sys/epoll.h>
#include "epoller.hpp"
#include "connection.hpp"

class reactor
{
    const static int gnum = 64;

public:
    reactor()
        : _isrunning(false)
    {
    }
    //集合中添加连接，一切皆是连接思想
    void add_connection(int fd, uint32_t events, func_t recver, func_t sender, func_t excepter)
    {
        // 1. 构建connection
        connection *conn = new connection(fd);
        conn->set_event(events);
        conn->record(recver, sender, excepter);
        conn->set_self(this);
        // 2. 向内核中设置关心套接字 和 事件
        _epoller.add_event(conn->sockfd(), conn->events());
        // 3. 向_connection添加connection对象
        _connection.insert(std::make_pair(conn->sockfd(), conn));
    }
    //判断文件描述是否在集合中
    bool connection_is_exists(int sockfd)
    {
        auto iter = _connection.find(sockfd);
        return iter != _connection.end();
    }
    //断开连接
    void remove_connection(int sockfd)
    {
        // 判断文件描述符是否存在
        if (!connection_is_exists(sockfd))
            return;
        // 1. 去掉对文件描述符的关心
        _epoller.del_event(sockfd);
        // 2. 服务器关闭sockfd
        _connection[sockfd]->sockfd_close();
        // 3. 释放connection
        delete _connection[sockfd];
        _connection.erase(sockfd); // 删除kv
    }
    void enable_read_write(int sockfd, bool readable, bool writeable)
    {
        uint32_t events = (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET;
        if (connection_is_exists(sockfd))
            ;
        {
            // 1. 修改connection关心的事件
            _connection[sockfd]->set_event(events);
            // 2. 写到内核中
            _epoller.mode_event(sockfd, events);
        }
    }
    //等待事件发生，并处理
    void loop_once(int timeout)
    {
        int n = _epoller.wait(event, gnum, timeout); // 等待事件发生，n表示有几个事件发生
        for (int i = 0; i < n; i++)
        {
            int sockfd = event[i].data.fd;
            uint32_t revents = event[i].events;
            if (revents & EPOLLHUP) // 如果revents变量中包含EPOLLHUP事件：挂起事件网络连接另一端关闭连接，
                // EPOLLIN 和 EPOLLOUT 事件添加到 revents 变量中
                // 为什么？即使没有数据可读或可写，当连接被挂起时仍然想要读取剩余的数据或尝试发送数据
                revents |= (EPOLLIN | EPOLLOUT); // EPOLLIN 和 EPOLLOUT 可读或可写事件添加到revents中
            if (revents & EPOLLERR)              // 底层文件描述符发生了某种错误状态
                // EPOLLIN 和 EPOLLOUT 事件会被添加到 revents 中
                // 原因：可能想要检查套接字上是否有数据可读（可能包含错误信息），或者尝试发送数据（尽管可能发送失败）
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLIN) // 可读事件发生
            {
                // 检查_connection中是否有发生事件文件描述符sockfd，和 处理方法_recver
                if (connection_is_exists(sockfd) && (_connection[sockfd]->_recver != nullptr))
                {
                    _connection[sockfd]->_recver(_connection[sockfd]); // 本质是调用：accepter函数
                }
            }
            if (revents & EPOLLOUT) // 可写事件发生
            {
                // 检查_connection中是否有发生事件文件描述符sockfd，和 处理方法_sender
                if (connection_is_exists(sockfd) && (_connection[sockfd]->_sender != nullptr))
                {
                    _connection[sockfd]->_sender(_connection[sockfd]);
                }
            }
        }
    }
    void debug()
    {
        std::cout << "-------------------------" << std::endl;
        for (auto &connection : _connection)
        {
            std::cout << "fd: " << connection.second->sockfd() << ", ";
            uint32_t events = connection.second->events();
            if ((events & EPOLLIN) && (events & EPOLLET))
                std::cout << "EPOLLIN | EPOLLET";
            if ((events & EPOLLOUT) && (events & EPOLLET))
                std::cout << "EPOLLOUT | EPOLLET";
            std::cout << std::endl;
        }
        std::cout << "-------------------------" << std::endl;
    }
    // 事件派发核心函数
    void dispatcher()
    {
        _isrunning = true;
        int timeout = 3000;
        while (_isrunning)
        {
            loop_once(timeout);
            // 处理其他事情
            debug();
        }
        _isrunning = false;
    }
    ~reactor()
    {
    }

private:
    std::unordered_map<int, connection *> _connection;//文件描述符 和 事件处理方法集
    struct epoll_event event[gnum]; // 事件集合
    epoller _epoller;
    bool _isrunning;
};